package com.ant.storage.service.impl;

import com.ant.storage.common.ResultCode;
import com.ant.storage.common.ResultVo;
import com.ant.storage.dto.DepreciationDto;
import com.ant.storage.handler.AntException;
import com.ant.storage.mapper.DepreciationMapper;
import com.ant.storage.pojo.CarInfo;
import com.ant.storage.pojo.Depreciation;
import com.ant.storage.pojo.DepreciationDetails;
import com.ant.storage.pojo.UserInfo;
import com.ant.storage.service.ICarInfoService;
import com.ant.storage.service.IDataMsgService;
import com.ant.storage.service.IDepreciationDetailsService;
import com.ant.storage.service.IDepreciationService;
import com.ant.storage.utils.DateFormat;
import com.ant.storage.utils.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.validation.BindingResult;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletContext;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author melon
 * @since 2023-12-23
 */
@Service
public class DepreciationServiceImpl extends ServiceImpl<DepreciationMapper, Depreciation> implements IDepreciationService {

    @Autowired
    private IDataMsgService changeDb;

    @Value("${loginUrl.url}")
    private String Url;
    @Autowired
    public ServletContext servletContext;

    @Autowired
    public IDepreciationDetailsService detailsService;

    @Autowired
    public IDepreciationService depreciationService;


    @Autowired
    public ICarInfoService carInfoService;

    @Override
    public PageInfo<Depreciation> queryList(DepreciationDto dto) {
        try {
            UserInfo userInfo = (UserInfo) servletContext.getAttribute("userInfo");
            PageHelper.startPage(dto.getPageIndex(), dto.getPageSize());
            QueryWrapper<Depreciation> wrapper = new QueryWrapper<>();
            if (dto.getCityId() != null) {
                wrapper.lambda().in(Depreciation::getCityId, dto.getCityId());
            }
            if (dto.getCompanyId() != null) {
                wrapper.lambda().eq(Depreciation::getCompanyId, dto.getCompanyId());
            }
            if (StringUtils.isNotEmpty(dto.getContractNumber())) {
                wrapper.lambda().eq(Depreciation::getPropertyCode, dto.getContractNumber());
            }
            if (dto.getStatus() != null) {
                wrapper.lambda().eq(Depreciation::getStatus, dto.getStatus());
            }
            if (dto.getIsPeriods() != null) {
                if (dto.getIsPeriods() == 1) {
                    wrapper.lambda().gt(Depreciation::getPeriods, 0);
                } else {
                    wrapper.lambda().eq(Depreciation::getPeriods, 0);
                }
            }

            if (dto.getTime() != null && dto.getTime().size() > 0) {
                wrapper.lambda().between(Depreciation::getCreationTime,
                        dto.getTime().get(0) + " 00:00:00",
                        dto.getTime().get(1) + " 23:59:59");
            }
            if (userInfo.getRoles() == null) {
                wrapper.lambda().eq(Depreciation::getCityId, userInfo.getCityId()).or().eq(Depreciation::getCreateBy,
                        userInfo.getNameId());
            }
            if (userInfo.getRoles() != null && userInfo.getRoles().equals("admin")) {
                wrapper.lambda().eq(Depreciation::getCityId, userInfo.getCityId());
            }
            wrapper.orderByDesc("id");
            List<Depreciation> list = this.baseMapper.selectList(wrapper);
            PageInfo<Depreciation> pageInfo = new PageInfo<>(list);
            return pageInfo;
        } catch (Exception e) {
            throw new AntException(ResultCode.BODY_NOT_MATCH.getResultCode(), e.getMessage());
        }
    }

    @Override
    public ResultVo DepreciationSave(Depreciation dto, BindingResult result) {
        synchronized (this) {
            if (result.hasErrors()) {
                throw new AntException(result.getFieldError().getDefaultMessage());
            } else {
                UserInfo userInfo = (UserInfo) servletContext.getAttribute("userInfo");
                // 是否报名
                dto.setPropertyCode("ANT-" + RandomUtil.generateNumber(5));
                dto.setCityId(userInfo.getCityId());
                dto.setCreateBy(userInfo.getNameId().toString());
                dto.setCreationTime(new Date());
                if (dto.getId() == null) {
                    this.baseMapper.insert(dto);
                } else {
                    this.baseMapper.updateById(dto);
                }
                return ResultVo.success("操作成功");
            }
        }
    }

    @Override
    public Depreciation findDepreciationById(Integer id) {
        if (id == null) {
            throw new AntException(ResultCode.FAILURE.getResultCode(), "参数错误");
        } else {
            Depreciation one = this.baseMapper.selectOne(new QueryWrapper<Depreciation>().eq("id", id));
            if (one == null) {
                throw new AntException(ResultCode.FAILURE.getResultCode(), "数据不存在");
            }
            return one;
        }
    }


    @Override
//    @DS("car")
    public List<DepreciationDetails> findCarInfoList() throws Exception {
        changeDb.changeDb(1003);
        try {
            LambdaQueryWrapper<CarInfo> wrapper = new LambdaQueryWrapper<>();
            wrapper.gt(CarInfo::getResidueDepreciationTime, 0);
            List<CarInfo> list = carInfoService.list(wrapper);
            List<DepreciationDetails> detailsList = list.stream().map(item -> {
                // 折扣金额
                BigDecimal amount =
                        new BigDecimal(item.getPurchaseMoney()).
                                divide(new BigDecimal(item.getDepreciationTime()), 2, BigDecimal.ROUND_HALF_UP);
                // 已经折扣期限
                Integer num = item.getDepreciationTime() - item.getResidueDepreciationTime();
                // 累计折扣金额
                BigDecimal accumulatedAmount = amount.multiply(new BigDecimal(num));
                DepreciationDetails details = new DepreciationDetails();
                details.setDepreciationId(item.getId());
                details.setCityId(item.getCityId());
                details.setDepId(item.getCompanyId());
                details.setDepreciationName(item.getLicenseNumber()); // licenseNumber
                details.setAmount(amount.setScale(2, BigDecimal.ROUND_HALF_UP));
                details.setAccumulatedAmount(accumulatedAmount.setScale(2, BigDecimal.ROUND_HALF_UP));
                details.setPeriodsAmount(item.getDepreciationTime());
                details.setPeriods(num + 1);
                details.setPeriodsCode(DateFormat.getCurrentDate());
                details.setPurchaseTime(item.getPurchaseTime());
                details.setPurchaseAmount(new BigDecimal(item.getPurchaseMoney()));
                details.setCreateBy("admin");
                details.setCreationTime(new Date());
                return details;
            }).collect(Collectors.toList());
            return detailsList;
        } catch (Exception e) {
            throw new AntException(ResultCode.BODY_NOT_MATCH.getResultCode(), e.getMessage());
        }
    }

    @Override
//    @DS("first")
    public void saveDepreciation(List<DepreciationDetails> carInfoList, Integer tid) throws Exception {
        changeDb.changeDb(1003);
        UserInfo userInfo = (UserInfo) servletContext.getAttribute("userInfo");
        List<DepreciationDetails> collect = carInfoList.stream().map(item -> {
            DepreciationDetails last = detailsService.last(item.getDepreciationId(), tid);
            String str = item.getPurchaseTime().substring(0, 10);
            List<Integer> list = calculateMonths(DateFormat.monthOne(str));
            item.setAnnuaPeriods(list.get(0)); // 本年累计
            item.setAnnualCumulative(list.get(1)); //年度累计
            item.setAnnual(list.get(2));
            int per = 1;
            if (last == null) {
                item.setStartTime(DateFormat.monthOne(str));
                item.setPeriods(per);
            } else {
                item.setPeriods(last.getPeriods() + 1);
                item.setStartTime(last.getStartTime());
                per = last.getPeriods() + 1;
            }
            item.setDepId(userInfo.getDepId());
            item.setTypes(tid);

            int pers = item.getPeriodsAmount() - per;
            BigDecimal accumulated_amount = item.getAmount().multiply(new BigDecimal(per));
            depreciationService.update(new UpdateWrapper<Depreciation>()
                    .set("amount", item.getAmount())
                    .set("accumulated_amount", accumulated_amount)
                    .set("periods", pers).eq("id", item.getDepreciationId()));
            return item;
        }).collect(Collectors.toList());
        detailsService.saveBatch(collect);
    }


    @Override
    public List<DepreciationDetails> findDepreciationList() {
        QueryWrapper<Depreciation> wrapper = new QueryWrapper<>();
        wrapper.gt("periods", "0");
        List<Depreciation> list = this.baseMapper.selectList(wrapper);
        List<DepreciationDetails> detailsList = list.stream().map(item -> {
            BigDecimal amount = item.getPurchaseAmount().divide(new BigDecimal(item.getPeriodsAmount()), 2,
                    BigDecimal.ROUND_HALF_UP);
            // 已经折扣期限
            Integer num = item.getPeriodsAmount() - item.getPeriods();
            BigDecimal accumulatedAmount = amount.multiply(new BigDecimal(num + 1)) ;
            DepreciationDetails details = new DepreciationDetails();
            details.setDepreciationId(item.getId());
            details.setCityId(item.getCityId());
            details.setDepId(item.getCompanyId());
            details.setDepreciationName(item.getPropertyName()); // licenseNumber
            details.setAmount(amount.setScale(2, BigDecimal.ROUND_HALF_UP)); // 折旧金额
            details.setAccumulatedAmount(accumulatedAmount.setScale(2, BigDecimal.ROUND_HALF_UP)); // 累计金额
            details.setPeriodsAmount(item.getPeriodsAmount());
            details.setPeriods(num + 1);
            details.setPeriodsCode(DateFormat.getCurrentDate());
            details.setPurchaseTime(DateFormat.simpleDateFormat(item.getPurchaseTime()));
            //details.setPurchaseTime(item.getPurchaseTime());
            details.setPurchaseAmount(item.getPurchaseAmount()); // 购买金额
            details.setCreateBy("admin");
            details.setCreationTime(new Date());
            return details;
        }).collect(Collectors.toList());
        return detailsList;
    }

    public static List<Integer> calculateMonths(String time) {
        Integer year = Integer.parseInt(time.substring(0, 4));// 年份
        Integer moths = Integer.parseInt(time.substring(5, 7));// 月
        LocalDate today = LocalDate.now();
        Integer endYear = today.getYear(); // 截止年份
        Integer endMonth = today.getMonthValue(); // 截止年份
        Integer a1 = 0;
        Integer a2 = 0;
        List<Integer> yearsBetween = DateFormat.getYearsBetween(year, endYear);
        //计算整年
        if (yearsBetween.size() - 2 >= 1) {
            a1 = yearsBetween.size() - 2;
        }
        //计算不到一年的
        if (year.equals(endYear) ){
            a2 = (endMonth - moths) == 0 ? 0 : (endMonth - moths);
        } else {
            a2 = (12 - moths) == 0 ? 0 : (12 - moths) + 1;
        }
        int annualCumulative = ((a1 * 12) + a2) > 12 ? 1 : (a1 * 12) + a2;
       // int annualCumulative =(a1 * 12) + a2;
        List<Integer> list = new ArrayList<>();
        list.add(endMonth); // 本年累计
        list.add(annualCumulative); // 年度累计
        list.add(annualCumulative + endMonth); // annual
        return list;
    }

    @Override
    public ResultVo uploadDepreciation(MultipartFile file) {
        Depreciation depreciation;//定义员工POJO类
        UserInfo userInfo = (UserInfo) servletContext.getAttribute("userInfo");
        //解析出来的封装好要返回的对象
        List<Depreciation> depreciationList = new ArrayList<>();
        //插入数据库时，需要日期格式转换
        SimpleDateFormat format = new SimpleDateFormat("yyyy-mm-dd");
        if (file.isEmpty()) {
            // 先判断客户端上传的excel有没有效
            throw new RuntimeException("文件错误");
        }
        try {
            //获得上传的excel文件
            //HSSFWorkbook workbook = new HSSFWorkbook(new POIFSFileSystem(file.getInputStream()));
            XSSFWorkbook workbook = new XSSFWorkbook(file.getInputStream());
            //获取第一个sheet
            XSSFSheet sheet = workbook.getSheetAt(0);
            //获取行数
            int rowNums = sheet.getPhysicalNumberOfRows();
            //遍历行数
            for (int i = 1; i < rowNums; i++) {
                depreciation = new Depreciation();
                //得到该行的数据
                XSSFRow row = sheet.getRow(i);
                if (row != null) {
                    //获得该行的单元格数量，并遍历出单元格
                    int cellNums = row.getPhysicalNumberOfCells();
                    for (int j = 0; j < cellNums; j++) {
                        XSSFCell cell = row.getCell(j);
                        cell.setCellType(CellType.STRING);
                        if (cell != null) {
                            //开始填装Emp实体属性
                            String value = cell.getStringCellValue();
                            if (value == null) {
                                value = "";//如果值是空的则空字符串
                            }
                            //每一个字段对应的index

                            switch (j) {
                                case 0:
                                    depreciation.setPropertyName(value);
                                    break;
                                case 1:
                                    depreciation.setPropertyType(value);
                                    break;
                                case 2:
                                    depreciation.setPropertyUnit(value);
                                    break;
                                case 3:
                                    depreciation.setPropertyAmount(Integer.parseInt(value == "" ? "0" : value));
                                    break;
                                case 4:
                                    depreciation.setUseTo(value);
                                    break;
                                case 5:
                                    depreciation.setDepreciationMethod(value);
                                    break;
                                case 6:
                                    depreciation.setDepreciationPeriod(Integer.parseInt(value == "" ? "0" : value));
                                    break;
                                case 7:
                                    depreciation.setPurchaseTime(format.parse(value));
                                    break;
                                case 8:
                                    depreciation.setUsedDate(format.parse(value));
                                    break;
                                case 9:
                                    depreciation.setPurchaseAmount(new BigDecimal(value));
                                    break;
                                case 10:
                                    depreciation.setStorageLocation(value);
                                    break;
                                case 11:
                                    depreciation.setChangeMethod(value);
                                    break;
                                case 12:
                                    depreciation.setAssetAccount(value);
                                    break;
                                case 13:
                                    depreciation.setPeriodsAmount(Integer.parseInt(value == "" ? "0" : value));
                                    break;
                                case 14:
                                    depreciation.setPeriods(Integer.parseInt(value == "" ? "0" : value));
                                    break;
                                case 15:
                                    depreciation.setAmount(new BigDecimal(value));
                                    break;
                                case 16:
                                    depreciation.setAccumulatedAmount(new BigDecimal(value));
                                    break;
                                case 17:
                                    depreciation.setStatus(value);
                                    break;
                                case 18:
                                    depreciation.setNotes(value);
                                    break;
                            }
                            depreciation.setPropertyCode("ANT-" + RandomUtil.generateNumber(5));
                            depreciation.setCityId(userInfo.getCityId());
                            depreciation.setCompanyId(userInfo.getDepId());
                            depreciation.setCreateBy(userInfo.getNameId().toString());
                            depreciation.setCreationTime(new Date());
                        }
                    }
                    this.baseMapper.insert(depreciation);
                    // depreciationService.save(depreciation);
                    //depreciationList.add(depreciation);
                }
            }
            return ResultVo.success("上传成功");

        } catch (Exception e) {
            e.printStackTrace();
            throw new AntException(ResultCode.BODY_NOT_MATCH);
        }
    }

    public static void main(String[] args) {
        List<Integer> list = calculateMonths("2023-11-01");
        System.out.println(list);
    }

}
